package no.ntnu.fp.gui.calendar;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.swing.JPanel;
import no.ntnu.fp.model.Appointment;
import no.ntnu.fp.model.Employee;
import no.ntnu.fp.model.Meeting;
import no.ntnu.fp.utils.ColorGenerator;
import no.ntnu.fp.utils.Participant;


@SuppressWarnings("serial")
public class DayPanel extends JPanel implements MouseListener, MouseMotionListener {
	private Map<RoundRectangle2D, Appointment> appointmentRectangles;
	private Map<Employee, Color> employeeColor;
	private Employee currentEmployee;
	private ArrayList<Meeting> meetings;
	private ArrayList<Appointment> appointments;
	private static Appointment selectedAppointment;
	private PropertyChangeSupport pcs;

	public DayPanel(){
		appointmentRectangles = new HashMap<RoundRectangle2D, Appointment>();
		meetings = new ArrayList<Meeting>();
		appointments = new ArrayList<Appointment>();
		selectedAppointment = null;
		this.setPreferredSize(new Dimension(125, 1500));
		this.setBackground(Color.WHITE);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.currentEmployee = null;
		employeeColor = new HashMap<Employee, Color>();
		pcs = new PropertyChangeSupport(this);
	}
	public void setMeetings(ArrayList<Meeting> meetings){
		this.meetings = new ArrayList<Meeting>(meetings);
	}
	public void setAppointments(ArrayList<Appointment> appointments){
		this.appointments = new ArrayList<Appointment>(appointments);
	}
	public void addAppointment(Appointment a){
		this.appointments.add(a);
	}
	public static Appointment getSelectedAppointment(){
		return selectedAppointment;
	}
	public void addMeeting(Meeting m){
		this.meetings.add(m);
	}
	public void clear(){
		this.appointments.clear();
		this.meetings.clear();
		this.appointmentRectangles.clear();
		this.employeeColor.clear();
	}
	public void setEmployeeColor(Employee emp, Color c){
		employeeColor.put(emp, c);
	}
	public void setCurrentEmployee(Employee emp){
		this.currentEmployee = emp;
	}
	public static Appointment getCurrentAppointment(){
		return selectedAppointment;
	}
	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		appointmentRectangles.clear();
		Graphics2D g2d = (Graphics2D) g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

		double startX = this.getWidth() * 0.1;
		double width = this.getWidth() - startX * 2.2;
		double hourHeight = this.getHeight() / 24;
		double minuteHeight = hourHeight/60;
		int textHeight = g2d.getFontMetrics().getHeight();
		int textWidth = g2d.getFontMetrics().charWidth('W');

		g2d.setColor(Color.BLUE);
		for(int i = 1; i < 24; i++){
			int y = (int)hourHeight*i;
			g2d.drawLine(0, y, this.getWidth(), y);
		}
		g2d.setColor(Color.BLACK);
		g2d.setStroke(new BasicStroke(3));
		for(Meeting m : meetings){
			ArrayList<Employee> emps = new ArrayList<Employee>();
			for(Participant p : m.getParticipants()){
				if(p.isAttending() != null && p.isAttending()){
					emps.add(p.getEmployee());
				}
			}
			
			RoundRectangle2D r = constructRect(m, hourHeight, minuteHeight, startX, width);
			g2d.draw(r);
			if(m.getEmployee().equals(currentEmployee)){
				g2d.setColor(Color.RED);
			}else if(emps.contains(currentEmployee)){
				g2d.setColor(Color.BLUE);
			}
			else{
				g2d.setColor(ColorGenerator.getColor(m.getEmployee()));
			}
			if(m.equals(selectedAppointment)){
				g2d.setColor(Color.ORANGE);
			}
			g2d.fill(r);
			appointmentRectangles.put(r, m);
			drawText(m, g2d, textHeight, textWidth, r);
		}
		g2d.setColor(Color.BLACK);
		for(Appointment a : appointments){
			RoundRectangle2D r = constructRect(a, hourHeight, minuteHeight, startX, width);
			g2d.draw(r);
			if(a.getEmployee().equals(currentEmployee)){
				g2d.setColor(Color.GREEN);
			}else{
				g2d.setColor(ColorGenerator.getColor(a.getEmployee()));
			}
			if(a.equals(selectedAppointment)){
				g2d.setColor(Color.ORANGE);
			}
			g2d.fill(r);
			appointmentRectangles.put(r, a);
			drawText(a, g2d, textHeight, textWidth, r);
		}
	}
	private RoundRectangle2D constructRect(Appointment app, double hourHeight, double minuteHeight,
			double startX, double width){
		Calendar cal = Calendar.getInstance();
		cal.setTime(app.getStartTime());
		int startY = (int) (cal.get(Calendar.HOUR_OF_DAY) * hourHeight);
		startY += (int)cal.get(Calendar.MINUTE) * minuteHeight;
		cal.setTime(app.getEndTime());
		int endY = (int) (cal.get(Calendar.HOUR_OF_DAY) * hourHeight);
		endY += (int)cal.get(Calendar.MINUTE) * minuteHeight;
		int height = endY - startY;
		RoundRectangle2D r = new RoundRectangle2D.Double(startX, startY, 
				width, height, 10, 10);
		return r;
	}

	private void drawText(Appointment m, Graphics2D g2d, int textHeight, int textWidth, RoundRectangle2D r){
		DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.GERMAN);
		g2d.setColor(Color.BLACK);
		String startTime = timeFormat.format(m.getStartTime());
		String endTime = timeFormat.format(m.getEndTime());
		if(r.getHeight()/3 > textHeight){
			g2d.drawString(startTime,
					(int)(r.getWidth() - startTime.length())/2 - 10, (int) r.getY() + 15);
			if(m.getTitle().length()*textWidth > r.getWidth()){
				String title = shortenString(m.getTitle(), (int) r.getWidth()/textWidth);
				g2d.drawString(title, 
						(int) (r.getX() + 15), (int) (r.getY() + r.getHeight()/2));
			}else{
				g2d.drawString(m.getTitle(),
						(int)(r.getWidth() - m.getTitle().length()*textWidth)/2 + 7, (int) (r.getY() + r.getHeight()/2));
			}
			g2d.drawString(endTime,
					(int)(r.getWidth() - startTime.length())/2- 10, (int) ( r.getY() + r.getHeight() - 5));
		}else if(r.getHeight()/2 > textHeight){
			g2d.drawString(startTime,
					(int)(r.getWidth() - startTime.length())/2- 10, (int) r.getY() + 15);
			g2d.drawString(endTime,
					(int)(r.getWidth() - startTime.length())/2- 10, (int) ( r.getY() + r.getHeight() - 5));
		}else if(r.getHeight() > textHeight){
			if(m.getTitle().length()*textWidth > r.getWidth()){
				String title = shortenString(m.getTitle(), (int) r.getWidth()/textWidth);
				g2d.drawString(title, 
						(int) (r.getX() + 15), (int) (r.getY() + r.getHeight()/2) + 4);
			}else{
				g2d.drawString(m.getTitle(),
						(int)(r.getWidth() - m.getTitle().length()*textWidth)/2 + 7, (int) (r.getY() + r.getHeight()/2) + 4);
			}
		}
	}

	private String shortenString(String s, int width){
		String result = s.substring(0, width - 4);
		result += "...";
		return result;
	}
	
	public void addPropertyChangeListener(PropertyChangeListener listener){
		pcs.addPropertyChangeListener(listener);
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		boolean newSelection = false;
		Appointment oldAppointment = selectedAppointment;
		for(RoundRectangle2D r : appointmentRectangles.keySet()){
			if(r.contains(arg0.getPoint())){
				selectedAppointment = appointmentRectangles.get(r);
				newSelection = true;
				break;
			}
		}
		if(!newSelection){
			selectedAppointment = null;
		}
		CalendarPanel.getInstance().repaintAll();
		pcs.firePropertyChange("", oldAppointment, selectedAppointment);
	}
	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	@Override
	public void mouseMoved(MouseEvent arg0) {
		boolean newSelection = false;
		DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.GERMAN);
		for(RoundRectangle2D r : appointmentRectangles.keySet()){
			if(r.contains(arg0.getPoint())){
				Appointment selected = appointmentRectangles.get(r);
				String title = selected.getTitle(), description = selected.getDescription(), 
				startTime = timeFormat.format(selected.getStartTime()), 
				endTime = timeFormat.format(selected.getEndTime());
				DayPanel.this.setToolTipText("<html><b>Tittel:</b> " + title + "<br><b>Beskrivels:</b> " + description + 
						"<br><b>Start tid:</b> " + startTime + "<br><b>Slutt tid:</b> " + endTime + "</html>");
				newSelection = true;
				break;
			}
		}
		if(!newSelection){
			DayPanel.this.setToolTipText("");
		}
	}
}
